# @Time   : 2022/3/7 13:41
# @Author : Fioman
# @Phone  : 13149920693
# @Tips   : Talk is Cheap,Show me the code! ^_^^_^
# @Time   : 2022/1/18 15:00
# @Author : Fioman
# @Phone  : 13149920693
# @Tips   : Talk is Cheap,Show me the code! ^_^^_^

"""
二拼板的算法,主要包括首板尺寸确认,两拼板的识别问题,获取切线的函数
"""
import os
import time

from db_tools.db_handler import DbHandler
from vision_process.image_process_common import *
from vision_process.vision_helper import create_image_test_dir

db = DbHandler()
cp = ConfigParams()
upDownSlice4p = int(50 * cp.mm2pix)
leftRightSlice4p = int(35 * cp.mm2pix)
jointLineExtend = 20
innerToEdgeThres = 6  # 单位mm
minLineLength = int(20 * cp.mm2pix)  # 线条最短是多少,50个mm
lineLengthMin = 20 * cp.mm2pix
maxLineGap = 5

tryBeginIndex = 1

calcArgsNormal = {
    "1": [[2], 17, 11, 8, 18, [25, 40, 60, 120, 150], 0.2],
    "2": [[2], 17, 17, 8, 15, [10, 20, 40], 0],
    "3": [[12], 17, 11, 8, 15, [5, 10, 15, 20], 0],
    "4": [[10], 17, 11, 8, 15, [5, 10, 15, 20], 0],
    # "5": [[0], 17, 17, 8, 15, [3, 5, 10, 20, 40, 55], 0],
    # "6": [[1], 17, 17, 8, 15, [20, 40, 60, 80], 0.1] ,
}


def check_inner_board_4p(board, width, height, calcThresBig, calcThresSmall, boardColor, boardPos, upLeftBox, upRightBox, downLeftBox,
                         totalBoardBox, innerLine, extendMiddle, isFirstCheck, offset, totalBoard):
    """
    检测内框的位置信息是否正确,是偏大还是偏小还是其他的问题
    :param floodFill:
    :param width:
    :param height:
    :param calcThresBig:
    :param calcThresSmall:
    :param boardColor:
    :param boardPos:
    :param upLeftBox:
    :param upRightBox:
    :param downLeftBox:
    :param downRightBox:
    :param totalBoardBox:
    :param innerLine:
    :param extendMiddle:
    :param isFirstCheck:
    :param offset:
    :param totalBoard:
    :return:
    """
    global minLineLength, maxLineGap, lineLengthMin
    boardArea = width * height
    totalHeightPix, totalWidthPix = board.shape[:2]
    totalWidthMm, totalHeightMm = round(totalWidthPix / cp.mm2pix, 2), round(totalHeightPix / cp.mm2pix, 2)
    moveWidth13 = int(totalWidthPix * 0.15)
    moveWidthMid = int(totalWidthPix * 0.15)
    moveHeight = int(totalHeightPix * 0.15)
    w, h = totalBoardBox[1]
    widthHalf = int(w / 2)
    heightHalf = int(h / 2)

    res = {
        "result": "error",
        "box": None,
        "info": "",
        "calcSize": (totalWidthMm, totalHeightMm),
        "calcError": (0, 0)
    }
    widthMax = width / cp.mm2pix + calcThresBig
    widthMin = width / cp.mm2pix - calcThresSmall
    heightMax = height / cp.mm2pix + calcThresBig
    heightMin = height / cp.mm2pix - calcThresSmall
    widthMm = width / cp.mm2pix
    heightMm = height / cp.mm2pix
    moveAngleUsed = board.copy()
    try:
        if boardPos == "upLeft" or boardPos == "upRight":
            cv.rectangle(moveAngleUsed, (0, 0), (moveWidth13, moveHeight), 0, -1)
            cv.rectangle(moveAngleUsed, (moveAngleUsed.shape[1], 0), (moveAngleUsed.shape[1] - moveWidth13, moveHeight), 0, -1)
            cv.rectangle(moveAngleUsed, (0, moveAngleUsed.shape[0] - moveHeight), (moveWidthMid, moveAngleUsed.shape[0]), 0, -1)
            cv.rectangle(moveAngleUsed, (moveAngleUsed.shape[1] - moveWidthMid, moveAngleUsed.shape[0] - moveHeight),
                         (moveAngleUsed.shape[1], moveAngleUsed.shape[0]), 0, -1)
        else:
            cv.rectangle(moveAngleUsed, (0, 0), (moveWidthMid, moveHeight), 0, -1)
            cv.rectangle(moveAngleUsed, (moveAngleUsed.shape[1], 0), (moveAngleUsed.shape[1] - moveWidthMid, moveHeight), 0, -1)
            cv.rectangle(moveAngleUsed, (0, moveAngleUsed.shape[0] - moveHeight), (moveWidth13, moveAngleUsed.shape[0]), 0, -1)
            cv.rectangle(moveAngleUsed, (moveAngleUsed.shape[1] - moveWidth13, moveAngleUsed.shape[0] - moveHeight),
                         (moveAngleUsed.shape[1], moveAngleUsed.shape[0]), 0, -1)

        image_show("MoveAngle", moveAngleUsed)

        cnts, _ = cv.findContours(moveAngleUsed.copy(), cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
        cntsSorted = sorted(cnts, key=cv.contourArea, reverse=True)
        if len(cnts) == 0:
            res["result"] = "error"
            res["info"] = "{}框 找内板失败,没有找到任何的轮廓".format(boardPos)
            res["calcSize"] = (totalWidthMm, totalHeightMm)
            res["calcError"] = (round(totalWidthMm - widthMm, 2), round(totalHeightMm - heightMm, 2))
            return res
        cntFindAgain = False  # 是否要再找一遍轮廓
        _, (w, h), _ = cv.minAreaRect(cntsSorted[0])
        rectBox = cv.minAreaRect(cntsSorted[0])
        rectBoxPoints = np.intp(cv.boxPoints(rectBox))
        leftTop, rightTop, rightBottom, leftBottom = get_rect_points_clockwise(rectBoxPoints)
        useImage = boardColor.copy()
        cv.drawContours(useImage, [rectBoxPoints], -1, (0, 255, 0), 3)
        image_show("InnerBoardFinded", useImage)
        res["box"] = [leftTop, rightTop, rightBottom, leftBottom]
        widthFinded = round(get_two_point_distance(leftTop, rightTop) / cp.mm2pix, 2)
        heightFinded = round(get_two_point_distance(leftTop, leftBottom) / cp.mm2pix, 2)
        res["calcSize"] = (widthFinded, heightFinded)
        res["calcError"] = (round(widthFinded - widthMm, 2), round(heightFinded - heightMm, 2))
        areaFinded = w * h
        if areaFinded < 0.7 * boardArea:
            res["result"] = "error"
            res["info"] = "{}框 找内板失败,找到的内板面积过小".format(boardPos)
            return res
        elif areaFinded > 1.3 * boardArea:
            res["result"] = "error"
            res["info"] = "{}框 找内板失败,找到的内板面积过大".format(boardPos)
            return res
        else:
            # 获取到物料边缘的距离,四个距离
            innerLine1 = [leftTop, rightTop]
            innerLine2 = [rightTop, rightBottom]
            innerLine3 = [rightBottom, leftBottom]
            innerLine4 = [leftBottom, leftTop]

            # 外层物料的四个顶点
            outterLine1 = [(0, 0), (totalWidthPix, 0)]
            outterLine2 = [(totalWidthPix, 0), (totalWidthPix, totalHeightPix)]
            outterLine3 = [(totalWidthPix, totalHeightPix), (0, totalHeightPix)]
            outterLine4 = [(0, totalHeightPix), (0, 0)]

            offsetTop = get_two_line_distance(innerLine1, outterLine1) / cp.mm2pix
            offsetRight = get_two_line_distance(innerLine2, outterLine2) / cp.mm2pix
            offsetBottom = get_two_line_distance(innerLine3, outterLine3) / cp.mm2pix
            offsetLeft = get_two_line_distance(innerLine4, outterLine4) / cp.mm2pix

            print("offsetMm: ({:.2f},{:.2f},{:.2f},{:.2f}), offsetPix: ({},{},{},{})".format(
                offsetTop, offsetRight, offsetBottom, offsetLeft, int(offsetTop * cp.mm2pix), int(offsetRight * cp.mm2pix),
                int(offsetBottom * cp.mm2pix), int(offsetLeft * cp.mm2pix)))
            if boardPos == "upLeft" or boardPos == "upRight":
                offsetTopLimit = 10
                offsetBottomLimit = upDownSlice4p / cp.mm2pix - 15
            else:
                offsetTopLimit = upDownSlice4p / cp.mm2pix - 15
                offsetBottomLimit = 10
            offsetLeftLimit = 10
            offsetRightLimit = 10

            findLineForMiddleFlag = False  # 中缝是否是通过找线来推测的
            # 推测第一边,如果找到的区域太靠近边缘,就重新找一次
            if offsetTop < offsetTopLimit and offsetBottom > offsetBottomLimit:
                findLineBoard = board.copy()[:int(board.shape[0] * 0.3), :]
                cv.destroyAllWindows()
                image_show("FindTopLineByLine", findLineBoard)
                scharrX = cv.Scharr(findLineBoard, cv.CV_64F, 1, 0)
                scharrY = cv.Scharr(findLineBoard, cv.CV_64F, 0, 1)
                scharrX = cv.convertScaleAbs(scharrX)
                scharrY = cv.convertScaleAbs(scharrY)
                scharrXY = cv.addWeighted(scharrX, 0.1, scharrY, 0.2, 0)
                findLineBoard = scharrXY.copy()
                image_show("ScharrXYFindTopLine", findLineBoard)
                lines = cv.HoughLinesP(findLineBoard, 1, np.pi / 180, 100, minLineLength, maxLineGap)
                boardShow = boardColor.copy()
                linesList = []
                colorIndex = 0
                for line in lines:
                    for x1, y1, x2, y2 in line:
                        lineLength = get_two_point_distance((x1, y1), (x2, y2))
                        if boardPos == "upLeft" or boardPos == "upRight":
                            yMin = 8 * cp.mm2pix
                            yMax = board.shape[0] - height - 10 * cp.mm2pix
                        else:
                            yMin = upDownSlice4p + 5 * cp.mm2pix
                            yMax = upDownSlice4p + 40 * cp.mm2pix
                        if abs(y2 - y1) < 5 * cp.mm2pix and abs(x2 - x1) > 10 * cp.mm2pix and yMin < y1 < yMax \
                                and yMin < y2 < yMax and lineLength > lineLengthMin:
                            linesList.append([x1, y1])
                            linesList.append([x2, y2])
                            cv.line(boardShow, (x1, y1), (x2, y2), colorList[colorIndex % 3], 3)
                            colorIndex += 1
                if len(linesList) >= 2:
                    image_show("TopLineFinded", boardShow)
                    cntFindAgain = True
                    if (boardPos == "upLeft" or boardPos == "upRight") and not innerLine:
                        linesListFinal = sorted(linesList, key=lambda x: x[1])
                    else:
                        linesListFinal = sorted(linesList, key=lambda x: x[1], reverse=True)
                        findLineForMiddleFlag = True

                    targetLine = [linesListFinal[0], linesListFinal[1]]
                    y1 = targetLine[0][1]
                    y2 = targetLine[1][1]
                    # 按照最小的那个去截取
                    slicePos = int(min(y1, y2))
                    moveAngleUsed[:slicePos, :] = 0
                    image_show("moveAngleAfterSliceTop", moveAngleUsed)

            # 如果第一边是对的,推测第三边
            if offsetTop > offsetTopLimit and offsetBottom < offsetBottomLimit:
                yOffset = int(board.shape[0] * 0.5)
                findLineBoard = board.copy()[yOffset:, :]
                cv.destroyAllWindows()
                image_show("FindBottomLineByLine", findLineBoard)
                scharrX = cv.Scharr(findLineBoard, cv.CV_64F, 1, 0)
                scharrY = cv.Scharr(findLineBoard, cv.CV_64F, 0, 1)
                scharrX = cv.convertScaleAbs(scharrX)
                scharrY = cv.convertScaleAbs(scharrY)
                scharrXY = cv.addWeighted(scharrX, 0.1, scharrY, 0.2, 0)
                findLineBoard = scharrXY.copy()
                image_show("ScharrXYFindBottomLine", findLineBoard)
                lines = cv.HoughLinesP(findLineBoard, 1, np.pi / 180, 100, minLineLength, maxLineGap)
                boardShow = boardColor.copy()
                linesList = []
                colorIndex = 0
                for line in lines:
                    for x1, y1, x2, y2 in line:
                        y1 += yOffset
                        y2 += yOffset
                        lineLength = get_two_point_distance((x1, y1), (x2, y2))
                        if boardPos == "upLeft" or "upRight":
                            yMin = boardShow.shape[0] - upDownSlice4p - 30 * cp.mm2pix
                            yMax = boardShow.shape[0] - upDownSlice4p + 5 * cp.mm2pix
                        else:
                            yMin = board.shape[0] - 100 * cp.mm2pix
                            yMax = board.shape[0] - 10 * cp.mm2pix

                        if abs(y2 - y1) < 5 * cp.mm2pix and abs(x2 - x1) > 10 * cp.mm2pix and yMin < y1 < yMax \
                                and yMin < y2 < yMax and lineLength > lineLengthMin:
                            linesList.append([x1, y1])
                            linesList.append([x2, y2])
                            cv.line(boardShow, (x1, y1), (x2, y2), colorList[colorIndex % 3], 3)
                            colorIndex += 1
                if len(linesList) >= 2:
                    image_show("BottomLineFinded", boardShow)
                    cntFindAgain = True
                    if boardPos == "upLeft" or boardPos == "upRight" or innerLine:
                        linesListFinal = sorted(linesList, key=lambda x: x[1])
                        if boardPos == "upLeft" or boardPos == "upRight":
                            findLineForMiddleFlag = True
                    else:
                        linesListFinal = sorted(linesList, key=lambda x: x[1], reverse=True)
                    targetLine = [linesListFinal[0], linesListFinal[1]]
                    y1 = targetLine[0][1]
                    y2 = targetLine[1][1]
                    slicePos = int(max(y1, y2))
                    moveAngleUsed[slicePos:, :] = 0
                    image_show("moveAngleAfterSliceBottom", moveAngleUsed)

            if widthFinded < widthMin or widthFinded > widthMax:  # 如果宽度识别的不对
                if (offsetRight > offsetRightLimit and offsetLeft < offsetLeftLimit) or innerLine:
                    # 推测左边的那条线
                    findLineBoard = board.copy()[:, :int(board.shape[1] * 0.2)]
                    cv.destroyAllWindows()
                    image_show("findLeftLineByLine", findLineBoard)
                    scharrX = cv.Scharr(findLineBoard, cv.CV_64F, 1, 0)
                    scharrY = cv.Scharr(findLineBoard, cv.CV_64F, 0, 1)
                    scharrX = cv.convertScaleAbs(scharrX)
                    scharrY = cv.convertScaleAbs(scharrY)
                    scharrXY = cv.addWeighted(scharrX, 0.2, scharrY, 0.1, 0)
                    findLineBoard = scharrXY.copy()
                    image_show("ScharrXYFindLeftLine", findLineBoard)
                    lines = cv.HoughLinesP(findLineBoard, 1, np.pi / 180, 100, minLineLength, maxLineGap)
                    boardShow = boardColor.copy()
                    linesList = []
                    colorIndex = 0
                    for line in lines:
                        for x1, y1, x2, y2 in line:
                            lineLength = get_two_point_distance((x1, y1), (x2, y2))
                            xMin = 10 * cp.mm2pix
                            xMax = boardShow.shape[1] * 0.3
                            if boardPos == "upLeft" or boardPos == "upRight":
                                yMin = 50 * cp.mm2pix
                                yMax = boardShow.shape[0] - upDownSlice4p - 30 * cp.mm2pix
                            else:
                                yMin = upDownSlice4p + 30 * cp.mm2pix
                                yMax = boardShow.shape[0] - 50 * cp.mm2pix
                            if abs(x2 - x1) < 5 * cp.mm2pix and abs(y2 - y1) > 10 * cp.mm2pix and xMin < x1 < xMax \
                                    and xMin < x2 < xMax and yMin < y1 < yMax and yMin < y2 < yMax and lineLength > lineLengthMin:
                                linesList.append([x1, y1])
                                linesList.append([x2, y2])
                                cv.line(boardShow, (x1, y1), (x2, y2), colorList[colorIndex % 3], 3)
                                colorIndex += 1

                    if len(linesList) >= 2:
                        image_show("LeftLineFinded", boardShow)
                        cntFindAgain = True
                        if innerLine:
                            linesListFinal = sorted(linesList, key=lambda x: x[0], reverse=True)
                        else:
                            linesListFinal = sorted(linesList, key=lambda x: x[0])

                        targetLine = [linesListFinal[0], linesListFinal[1]]
                        x1 = targetLine[0][0]
                        x2 = targetLine[1][0]
                        slicePos = int(min(x1, x2))
                        moveAngleUsed[:, :slicePos] = 0
                        image_show("moveAngleAfterSliceLeft", moveAngleUsed)

                if (offsetLeft > offsetLeftLimit and offsetRight < offsetRightLimit) or innerLine:
                    # 推测右边的那条线
                    xOffset = int(board.shape[1] * 0.75)
                    findLineBoard = board.copy()[:, xOffset:]
                    cv.destroyAllWindows()
                    image_show("findLeftLineByLine", findLineBoard)
                    scharrX = cv.Scharr(findLineBoard, cv.CV_64F, 1, 0)
                    scharrY = cv.Scharr(findLineBoard, cv.CV_64F, 0, 1)
                    scharrX = cv.convertScaleAbs(scharrX)
                    scharrY = cv.convertScaleAbs(scharrY)
                    scharrXY = cv.addWeighted(scharrX, 0.2, scharrY, 0.1, 0)
                    findLineBoard = scharrXY.copy()
                    image_show("ScharrXYFindRightLine", findLineBoard)
                    lines = cv.HoughLinesP(findLineBoard, 1, np.pi / 180, 100, minLineLength, maxLineGap)
                    boardShow = boardColor.copy()
                    linesList = []
                    colorIndex = 0
                    for line in lines:
                        for x1, y1, x2, y2 in line:
                            x1 += xOffset
                            x2 += xOffset
                            lineLength = get_two_point_distance((x1, y1), (x2, y2))
                            xMin = boardShow.shape[1] * 0.7
                            xMax = boardShow.shape[1] - 10 * cp.mm2pix
                            if boardPos == "upLeft" or boardPos == "upRight":
                                yMin = 50 * cp.mm2pix
                                yMax = boardShow.shape[0] - upDownSlice4p - 30 * cp.mm2pix
                            else:
                                yMin = upDownSlice4p + 30 * cp.mm2pix
                                yMax = boardShow.shape[0] - 50 * cp.mm2pix
                            if abs(x2 - x1) < 5 * cp.mm2pix and abs(y2 - y1) > 10 * cp.mm2pix and xMin < x1 < xMax and xMin < x2 < xMax \
                                    and lineLength > lineLengthMin and yMin < y1 < yMax and yMin < y2 < yMax:
                                linesList.append([x1, y1])
                                linesList.append([x2, y2])
                                cv.line(boardShow, (x1, y1), (x2, y2), colorList[colorIndex % 3], 3)
                                colorIndex += 1
                    if len(linesList) >= 2:
                        image_show("RightLineFinded", boardShow)
                        cntFindAgain = True
                        if innerLine:
                            linesListFinal = sorted(linesList, key=lambda x: x[0])
                        else:
                            linesListFinal = sorted(linesList, key=lambda x: x[0], reverse=True)

                        targetLine = [linesListFinal[0], linesListFinal[1]]
                        x1 = targetLine[0][0]
                        x2 = targetLine[1][0]
                        slicePos = int(max(x1, x2))
                        moveAngleUsed[:, slicePos:] = 0
                        image_show("moveAngleAfterSliceRight", moveAngleUsed)
            # 如果重新找线了,就再找一次轮廓
            if cntFindAgain:
                cnts, _ = cv.findContours(moveAngleUsed.copy(), cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
                cntsSorted = sorted(cnts, key=cv.contourArea, reverse=True)
                rectBox = cv.minAreaRect(cntsSorted[0])
                rectBoxPoints = np.intp(cv.boxPoints(rectBox))
                useImage = boardColor.copy()
                cv.drawContours(useImage, [rectBoxPoints], -1, (0, 255, 0), 3)
                image_show("InnerBoardFindedAfterFindLine", useImage)
                leftTop, rightTop, rightBottom, leftBottom = get_rect_points_clockwise(rectBoxPoints)
                res["box"] = leftTop, rightTop, rightBottom, leftBottom
                widthFinded = round(get_two_point_distance(leftTop, rightTop) / cp.mm2pix, 2)
                heightFinded = round(get_two_point_distance(leftTop, leftBottom) / cp.mm2pix, 2)
                res["calcSize"] = widthFinded, heightFinded
                res["calcError"] = round(widthFinded - widthMm, 2), round(heightFinded - heightMm, 2)

            topLineAngle = get_angle_by_k(get_line_k_and_b(leftTop, rightTop)[0])
            if abs(topLineAngle) > 20:
                res["result"] = "error"
                res["info"] = "识别的内框的第一边的角度太大,角度为:{:.2f}".format(topLineAngle)
                res["calcSize"] = (widthFinded, heightFinded)
                res["calcError"] = (round(widthFinded - widthMm, 2), round(heightFinded - heightMm, 2))
                return res
            resByExtendFlag = False
            # 再计算一次是否有错误的信息
            innerLine1 = [leftTop, rightTop]
            # innerLine2 = [rightTop, rightBottom]
            innerLine3 = [rightBottom, leftBottom]
            # innerLine4 = [leftBottom, leftTop]
            offsetTop = get_two_line_distance(innerLine1, outterLine1) / cp.mm2pix
            # offsetRight = get_two_line_distance(innerLine2, outterLine2) / cp.mm2pix
            offsetBottom = get_two_line_distance(innerLine3, outterLine3) / cp.mm2pix
            # offsetLeft = get_two_line_distance(innerLine4, outterLine4) / cp.mm2pix

            if extendMiddle:
                if ((boardPos == "upLeft" or boardPos == "upRight") and offsetTop > offsetTopLimit and (not heightMin < heightFinded < heightMax)) \
                        or ((boardPos == "downLeft" or boardPos == "downRight") and offsetBottom > offsetBottomLimit and
                            (not heightMin < heightFinded < heightMax)):
                    useImage = boardColor.copy()
                    newBox = get_new_box_by_edge_and_height([leftTop, rightTop, rightBottom, leftBottom], height, boardPos, useImage, upDownSlice4p)
                    if newBox is not None:
                        resByExtendFlag = True
                        res["box"] = newBox
                        leftTop, rightTop, rightBottom, leftBottom = newBox
                        widthFinded = round(get_two_point_distance(leftTop, rightTop) / cp.mm2pix, 2)
                        heightFinded = round(get_two_point_distance(leftTop, leftBottom) / cp.mm2pix, 2)
                        res["calcSize"] = (widthFinded, heightFinded)
                        res["calcError"] = round(widthFinded - widthMm, 2), round(heightFinded - heightMm, 2)
                        res["info"] = "识别成功,通过第一边推测中缝." if (boardPos == "upLeft" or boardPos == "upRight") else "识别成功,通过第三边推测中缝."
                        useImage = boardColor.copy()
                        cv.drawContours(useImage, [np.array(newBox)], -1, (0, 255, 0), 3)
                        image_show("InnerBoardFindedByExtendForMiddle", useImage)

            # 通过中缝推测另外一边,如果中缝不是推测的
            if (heightFinded < heightMin or heightFinded > heightMax) and widthMin < widthFinded < widthMax and not findLineForMiddleFlag:
                middlineY = get_two_points_middle(leftTop, rightTop)[1] if (boardPos == "downLeft" or boardPos == "downRight") else \
                    get_two_points_middle(leftBottom, rightBottom)[1]
                totalBoardMiddle = upDownSlice4p if (boardPos == "downLeft" or boardPos == "downRight") else board.shape[0] - upDownSlice4p

                if ((totalBoardMiddle - middlineY) > 5 * cp.mm2pix and (boardPos == "upLeft" or boardPos == "upRight")) or \
                        ((totalBoardMiddle - middlineY) < -15 * cp.mm2pix and (boardPos == "downLeft" or boardPos == "downRight")):
                    middleIsOk = True
                else:
                    middleIsOk = False

                if middleIsOk:
                    newBox = get_new_box_by_middle_and_height([leftTop, rightTop, rightBottom, leftBottom], height, boardPos, boardColor)
                    if newBox is not None:
                        res["box"] = newBox
                        resByExtendFlag = True
                        leftTop, rightTop, rightBottom, leftBottom = newBox
                        widthFinded = round(get_two_point_distance(leftTop, rightTop) / cp.mm2pix, 2)
                        heightFinded = round(get_two_point_distance(leftTop, leftBottom) / cp.mm2pix, 2)
                        res["calcSize"] = (widthFinded, heightFinded)
                        res["calcError"] = (round(widthFinded - widthMm, 2), round(heightFinded - heightMm, 2))
                        res["info"] = "识别成功,通过中缝推测第一边" if boardPos == "up" else "识别成功,通过中缝推测第三边"
            if isFirstCheck:
                if widthFinded < widthMin or heightFinded < heightMin:
                    res["result"] = "small"
                    res["info"] = "{} 框,识别尺寸过小,识别尺寸: {}".format(boardPos, res["calcSize"])
                    return res
                if widthFinded > widthMax or heightFinded > heightMax:
                    res["result"] = "big"
                    res["info"] = "{} 框,识别尺寸过大,识别尺寸: {}".format(boardPos, res["calcSize"])
                    return res
            else:
                if widthFinded < widthMin or widthFinded > widthMax:
                    otherLineIsOk, newBox = check_other_line_is_ok(board, res["box"], offset, "24", width, boardPos)
                    if otherLineIsOk:
                        res["box"] = newBox
                        resByExtendFlag = True
                        leftTop, rightTop, rightBottom, leftBottom = get_rect_points_clockwise(newBox)
                        widthFinded = round(get_two_point_distance(leftTop, rightTop) / cp.mm2pix, 2)
                        heightFinded = round(get_two_point_distance(leftTop, leftBottom) / cp.mm2pix, 2)
                        res["calcSize"] = widthFinded, heightFinded
                        res["calcError"] = round(widthFinded - widthMm, 2), round(heightFinded - heightMm, 2)
                        res["info"] = "识别成功,2,4边通过一边推测另外一边"
                        useImage = boardColor.copy()
                        cv.drawContours(useImage, [np.array(newBox)], -1, colorGreen, 3)
                        image_show("InnerBoardFindedByCalc24", useImage)
                    else:
                        if widthFinded < widthMin:
                            res["result"] = "small"
                            res["info"] = "宽度识别过小,识别尺寸:{},识别误差:{}".format(res["calcSize"], res["calcError"])
                            return res
                        if widthFinded > widthMax:
                            res["result"] = "big"
                            res["info"] = "宽度识别过大,识别尺寸:{},识别误差:{}".format(res["calcSize"], res["calcError"])
                            return res

                if heightFinded < heightMin or heightFinded > heightMax:
                    otherLineIsOk, newBox = check_other_line_is_ok(board, res["box"], offset, "13", height, boardPos)
                    if otherLineIsOk:
                        res["box"] = newBox
                        resByExtendFlag = True
                        leftTop, rightTop, rightBottom, leftBottom = get_rect_points_clockwise(newBox)
                        widthFinded = round(get_two_point_distance(leftTop, rightTop) / cp.mm2pix, 2)
                        heightFinded = round(get_two_point_distance(leftTop, leftBottom) / cp.mm2pix, 2)
                        res["calcSize"] = widthFinded, heightFinded
                        res["calcError"] = round(widthFinded - widthMm, 2), round(heightFinded - heightMm, 2)
                        res["info"] = "识别成功,1,3边通过一边推测另外一边"
                        useImage = boardColor.copy()
                        cv.drawContours(useImage, [np.array(newBox)], -1, colorGreen, 3)
                        image_show("InnerBoardFindedByCalc13", useImage)
                    else:
                        if heightFinded < heightMin:
                            res["result"] = "small"
                            res["info"] = "高度识别过小,识别尺寸:{},识别误差:{}".format(res["calcSize"], res["calcError"])
                            return res
                        if heightFinded > heightMax:
                            res["result"] = "big"
                            res["info"] = "高度识别过大,识别尺寸:{},识别误差:{}".format(res["calcSize"], res["calcError"])
                            return res

            # 再次计算一下有没有错误的边信息,主要是不是离物料边缘太近.
            innerLine1 = [leftTop, rightTop]
            innerLine2 = [rightTop, rightBottom]
            innerLine3 = [rightBottom, leftBottom]
            innerLine4 = [leftBottom, leftTop]
            offsetTop = get_two_line_distance(innerLine1, outterLine1) / cp.mm2pix
            offsetRight = get_two_line_distance(innerLine2, outterLine2) / cp.mm2pix
            offsetBottom = get_two_line_distance(innerLine3, outterLine3) / cp.mm2pix
            offsetLeft = get_two_line_distance(innerLine4, outterLine4) / cp.mm2pix
            if min(offsetTop, offsetRight, offsetBottom, offsetLeft) < 6:
                res["info"] = "识别的内框太靠近物料边缘: ({:.2f},{:.2f},{:.2f},{:.2f})".format(offsetTop, offsetRight, offsetBottom, offsetLeft)
                res["calcSize"] = widthFinded, heightFinded
                res["calcError"] = round(widthFinded - widthMm, 2), round(heightFinded - heightMm, 2)
                return res
            boxFinded = res["box"]
            if boardPos == "upRight":
                upRightBoxPoints = [(p[0] + widthHalf - leftRightSlice4p, p[1]) for p in boxFinded]
                # 检测是否叠板
                isOverlap = check_two_box_is_overlap(upLeftBox, upRightBoxPoints)
                if isOverlap:
                    totalBoardColor = cv.cvtColor(totalBoard, cv.COLOR_GRAY2BGR)
                    cv.drawContours(totalBoardColor, [np.array(upLeftBox), np.array(upRightBoxPoints)], -1, colorGreen, 3)
                    image_show("BoardOverLap", totalBoardColor)
                    res["result"] = "error"
                    res["info"] = "上下框出现叠板,识别失败~"
                    return res
            elif boardPos == "downLeft":
                downLeftBoxPoints = [(p[0], p[1] + heightHalf - upDownSlice4p) for p in boxFinded]
                isOverlap = check_two_box_is_overlap(downLeftBoxPoints, upLeftBox)
                if isOverlap:
                    totalBoardColor = cv.cvtColor(totalBoard, cv.COLOR_GRAY2BGR)
                    cv.drawContours(totalBoardColor, [np.array(upLeftBox), np.array(downLeftBoxPoints)], -1, colorGreen, 3)
                    image_show("BoardOverLap", totalBoardColor)
                    res["result"] = "error"
                    res["info"] = "上下框出现叠板,识别失败~"
                    return res
            elif boardPos == "downRight":
                downRightBoxPoints = [(p[0] + widthHalf - leftRightSlice4p, p[1] + heightHalf - upDownSlice4p) for p in boxFinded]
                downLeftBoxPoints = [(p[0], p[1] + heightHalf - upDownSlice4p) for p in downLeftBox]
                upRightBoxPoints = [(p[0] + widthHalf - leftRightSlice4p, p[1]) for p in upRightBox]
                isOverlap = check_two_box_is_overlap(downRightBoxPoints, downLeftBoxPoints)
                if isOverlap:
                    totalBoardColor = cv.cvtColor(totalBoard, cv.COLOR_GRAY2BGR)
                    cv.drawContours(totalBoardColor, [np.array(downRightBoxPoints), np.array(downLeftBoxPoints)], -1, colorGreen, 3)
                    image_show("BoardOverLap", totalBoardColor)
                    res["result"] = "error"
                    res["info"] = "上下框出现叠板,识别失败~"
                    return res

                isOverlap = check_two_box_is_overlap(downRightBoxPoints, upRightBoxPoints)
                if isOverlap:
                    totalBoardColor = cv.cvtColor(totalBoard, cv.COLOR_GRAY2BGR)
                    cv.drawContours(totalBoardColor, [np.array(downRightBoxPoints), np.array(upRightBoxPoints)], -1, colorGreen, 3)
                    image_show("BoardOverLap", totalBoardColor)
                    res["result"] = "error"
                    res["info"] = "上下框出现叠板,识别失败~"
                    return res

            if resByExtendFlag:
                res["result"] = "okByExtend"
            else:
                res["result"] = "ok"
                res["info"] = "识别成功!"
            return res
    except Exception as e:
        errorInfo = "in check_inner_board_2p(),error: {}".format(str(e))
        print(errorInfo)
        res["result"] = "error"
        res["info"] = errorInfo
        res["calcSize"] = (totalWidthMm, totalHeightMm)
        res["calcError"] = (round(totalWidthMm - width / cp.mm2pix, 2), round(totalHeightMm - height / cp.mm2pix, 2))
        return res


def get_inner_board_info_4p(board, jointLine1, jointLine2, width, height, calcThresBig, calcThresSmall, boardPos, isFirstCheck=False, upLeftBox=None,
                            upRightBox=None, downLeftBox=None, offset=None, isSizeCheck=False, totalBoard=None,
                            totalBoardBox=None):
    """
    获取内板信息,4拼板
    :param board:
    :param jointLine1:
    :param jointLine2:
    :param width:
    :param height:
    :param calcThresBig:
    :param calcThresSmall:
    :param boardPos:
    :param isFirstCheck:
    :param upLeftBox:
    :param upRightBox:
    :param downLeftBox:
    :param downRightBox:
    :param offset:
    :param isSizeCheck:
    :param totalBoard:
    :return:
    """
    boardColor = cv.cvtColor(board.copy(), cv.COLOR_GRAY2BGR)
    sizeOkByExtendRes = []
    sizeDifRes = []
    sizeOkRes = []
    calcArgs = calcArgsNormal

    for tryTimes in range(tryBeginIndex, len(calcArgs.keys()) + 1):
        cv.destroyAllWindows()
        gaussianR, squareR, dilateKernel, dilateTimes, erodeTimes, thresOffsetList, scharrRate = calcArgs.get(str(tryTimes))
        print("第{}次计算,计算参数:(高斯半径:{},方差核:{},膨胀腐蚀核:{},膨胀腐蚀次数:{},腐蚀膨胀次数:{},阈值offset:{},scharr比例:{})".format(
            tryTimes, gaussianR, squareR, dilateKernel, dilateTimes, erodeTimes, thresOffsetList, scharrRate))

        if len(gaussianR) == 1:
            if gaussianR[0] == 0:
                blurred = board.copy()
            else:
                blurred = cv.GaussianBlur(board, (0, 0), gaussianR[0])
        else:
            d, colorSigma = gaussianR
            spaceSigma = int(d / 2)
            blurred = cv.bilateralFilter(board, d, colorSigma, spaceSigma)

        if scharrRate == 0:
            scharrXY = blurred.copy()
        else:
            scharrX = cv.Scharr(blurred, cv.CV_64F, 1, 0)
            scharrY = cv.Scharr(blurred, cv.CV_64F, 0, 1)
            scharrX = cv.convertScaleAbs(scharrX)
            scharrY = cv.convertScaleAbs(scharrY)
            scharrXY = cv.addWeighted(scharrX, scharrRate, scharrY, scharrRate, 0)
            scharrXY = cv.convertScaleAbs(scharrXY)
            scharrXY = cv.bitwise_and(scharrXY, jointLine1)
        image_show("ScharrXY", scharrXY)
        img32 = np.float32(scharrXY)
        square1 = cv.blur(np.multiply(img32, img32), (squareR, squareR))
        square2 = np.multiply(cv.blur(img32, (squareR, squareR)), cv.blur(img32, (squareR, squareR)))
        squareDif32 = np.subtract(square1, square2)
        squareDif = squareDif32.copy()
        np.clip(squareDif32, 0, 255, out=squareDif)
        squareDif = squareDif.astype("uint8")
        image_show("SquareDif", squareDif)

        # 进行膨胀腐蚀,分割图像
        contourImg = squareDif.copy()
        kernelUsed = cv.getStructuringElement(cv.MORPH_RECT, (dilateKernel, dilateKernel))
        contourImg = cv.dilate(contourImg, kernelUsed, iterations=dilateTimes)
        contourImg = cv.erode(contourImg, kernelUsed, iterations=dilateTimes)
        image_show("squareDifDilateErore", contourImg)

        squareDifErode = contourImg.copy()
        for index, thresOffset in enumerate(thresOffsetList):
            cv.destroyAllWindows()
            image_show("squareDifDilateErode", squareDifErode)
            # 根据阈值进行分割
            centerX, centerY = int(squareDifErode.shape[1] / 2), int(squareDifErode.shape[0] / 2)
            yChoosePos = int(0.25 * squareDifErode.shape[0])
            xChoosePos = int(0.25 * squareDifErode.shape[1])
            thresUsed = squareDifErode[centerY - yChoosePos:centerY + yChoosePos, centerX - xChoosePos:centerX + xChoosePos]
            chooseRoiThres = int(np.mean(thresUsed))
            thresUsedReal = chooseRoiThres + thresOffset
            print("第 {} 个阈值,使用的实际阈值:{},参考的中心区域亮度值:{},thresOffset:{}".format(index + 1, thresUsedReal, chooseRoiThres, thresOffset))
            _, contourImg = cv.threshold(squareDifErode, thresUsedReal, 255, cv.THRESH_BINARY)

            # 如果是另外一种情况没有使用梯度的时候,拼接处的另外一种处理方式
            if scharrRate == 0:
                contourImg = cv.subtract(contourImg, jointLine2)

            # 4. 进行泛洪填充,要考虑一种情况是,填充选择的点刚好不是黑点,是个白点的情况.要重新再选一次
            mask = np.zeros((contourImg.shape[0] + 2, contourImg.shape[1] + 2), dtype=np.uint8)
            if contourImg[contourImg.shape[0] // 2, contourImg.shape[1] // 2] > 150:
                cv.floodFill(contourImg, mask, (contourImg.shape[1] // 3, contourImg.shape[0] // 3), 150)
            else:
                cv.floodFill(contourImg, mask, (contourImg.shape[1] // 2, contourImg.shape[0] // 2), 150)

            floodFill = np.zeros(contourImg.shape, dtype=np.uint8)
            floodFill[contourImg == 150] = 250
            image_show("FloodFill", floodFill)

            if len(gaussianR) == 1 and gaussianR[0] >= 10:
                innerLine = True  # 是否按照从内往外找
            else:
                innerLine = False

            if tryTimes == 4:
                extendMiddle = True
            else:
                extendMiddle = False

            # 进行腐蚀膨胀,去除掉边界的噪点
            floodFill = cv.erode(floodFill, kernelUsed, iterations=erodeTimes)
            floodFill = cv.dilate(floodFill, kernelUsed, iterations=erodeTimes)
            image_show("FloodFillErodeDilate", floodFill)
            res = check_inner_board_4p(floodFill, width, height, calcThresBig, calcThresSmall, boardColor, boardPos, upLeftBox,
                                       upRightBox, downLeftBox, totalBoardBox, innerLine, extendMiddle, isFirstCheck, offset,
                                       totalBoard)
            print("计算结果:{},{},识别尺寸:{},{},误差:{}".format(res["result"], res["info"], res["calcSize"],
                                                                 (int(res["calcSize"][0] * cp.mm2pix), int(res["calcSize"][1] * cp.mm2pix)), res["calcError"]))
            if res["result"] == "ok":
                sizeOkRes.append(res)
                calcSize = res["calcSize"]
                calcError = res["calcError"]
                if get_sum_abs(calcError) < 7 and not isSizeCheck:  # 如果不是做首片,并且误差之后小于7就直接返回
                    print("返回的ok结果是:算子编号和亮度阈值:({},{}),尺寸:{},{},误差:{}".format(tryTimes, thresOffset, calcSize,
                                                                                                (int(calcSize[0] * cp.mm2pix), int(calcSize[1] * cp.mm2pix)), calcError))
                    return "ok", res["info"], res["box"]
                continue
            elif res["result"] == "okByExtend":
                if isFirstCheck and isSizeCheck:
                    sizeOkRes.append(res)
                else:
                    sizeOkByExtendRes.append(res)
                continue
            elif res["result"] != "error":
                sizeDifRes.append(res)
                if res["result"] == "big" and not innerLine and not extendMiddle:
                    break
                if res["result"] == "small":
                    continue
                continue
    else:
        # 最外成循环都结束之后.
        if isFirstCheck and isSizeCheck:
            sizeList = []
            boxList = []
            if len(sizeOkRes) >= 1:
                resOkSorted = sorted(sizeOkRes, key=lambda x: get_sum_abs(x["calcError"]))
                for res in resOkSorted:
                    sizeList.append(res["calcSize"])
                    boxList.append(res["box"])
                return "ok", sizeList, boxList

            if len(sizeOkByExtendRes) >= 1:
                resOkSorted = sorted(sizeOkByExtendRes, key=lambda x: get_sum_abs(x["calcError"]))
                for res in resOkSorted:
                    sizeList.append(res["calcSize"])
                    boxList.append(res["box"])
                return "ok", sizeList, boxList

            if len(sizeDifRes) >= 1:
                resSizeDifList = sorted(sizeDifRes, key=lambda x: get_sum_abs(x["calcError"]))
                for res in resSizeDifList:
                    sizeList.append(res["calcSize"])
                    boxList.append(res["box"])
                return "sizeDif", sizeList, boxList

            else:
                return "error", "内板寻找失败", None
        else:
            if len(sizeOkRes) >= 1:
                resOkSorted = sorted(sizeOkRes, key=lambda x: get_sum_abs(x["calcError"]))
                res = resOkSorted[0]
                print("返回的ok结果是:尺寸:{},{},误差:{}".format(
                    res["calcSize"], (int(res["calcSize"][0] * cp.mm2pix), int(res["calcSize"][1] * cp.mm2pix)), res["calcError"]))
                return "ok", res["info"], res["box"]

            if len(sizeOkByExtendRes) >= 1:
                resOkSorted = sorted(sizeOkByExtendRes, key=lambda x: get_sum_abs(x["calcError"]))
                res = resOkSorted[0]
                print("返回的ok结果是:尺寸:{},{},误差:{}".format(
                    res["calcSize"], (int(res["calcSize"][0] * cp.mm2pix), int(res["calcSize"][1] * cp.mm2pix)), res["calcError"]))
                return "ok", res["info"], res["box"]

            if len(sizeDifRes) >= 1:
                resDifSorted = sorted(sizeDifRes, key=lambda x: get_sum_abs(x["calcError"]))
                res = resDifSorted[0]
                return "sizeDif", res["info"], res["box"]
            else:
                return "error", "找内板失败", None


def get_size_check_result_4p(image, width, height, calcThresBig, totalBoardBox, totalBoard):
    """
    六拼板获取尺寸确认的图片
    :param image:
    :param width:
    :param height:
    :param calcThresBig:
    :param totalBoardBox:
    :param totalBoard:
    :return:
    """
    print("函数 get_size_check_result_4p() 被调用,获取尺寸确认的图片")
    if image is None:
        return "error", None, None, None

    jointLineMask1 = np.ones(image.shape, dtype=np.uint8) * 255
    # 竖着进板的填充
    jointLineMask1[:, cp.middleJointPos - jointLineExtend:cp.middleJointPos + jointLineExtend] = 0
    # 横着进板的填充
    # jointLineMask1[cp.middleJointPos - jointLineExtend:cp.middleJointPos + jointLineExtend,:] = 0
    jointLineMaskNoAngle1, _ = get_board_without_angle(jointLineMask1, totalBoardBox)

    jointLineMask2 = np.zeros(image.shape, dtype=np.uint8)
    # 竖着进板的填充
    jointLineMask2[:, cp.middleJointPos02 - jointLineExtend:cp.middleJointPos02 + jointLineExtend] = 255
    # 横着进板的填充
    # jointLineMask2[cp.middleJointPos - jointLineExtend:cp.middleJointPos + jointLineExtend,:] = 255
    jointLineMaskNoAngle2, _ = get_board_without_angle(jointLineMask2, totalBoardBox)
    cv.destroyAllWindows()
    image_show("TotalBoard", totalBoard)

    w, h = totalBoardBox[1]
    heightHalf = int(h / 2)
    widthHalf = int(w / 2)
    upLeftBoard = totalBoard.copy()[:int(heightHalf + upDownSlice4p), :int(widthHalf + leftRightSlice4p)]
    upLeftBoardColor = cv.cvtColor(upLeftBoard, cv.COLOR_GRAY2BGR)
    jointLine1 = jointLineMaskNoAngle1.copy()[:int(heightHalf + upDownSlice4p), :int(widthHalf + leftRightSlice4p)]
    jointLine2 = jointLineMaskNoAngle2.copy()[:int(heightHalf + upDownSlice4p), :int(widthHalf + leftRightSlice4p)]

    upRes, upSizes, upBoxes = get_inner_board_info_4p(upLeftBoard, jointLine1, jointLine2, width, height, calcThresBig, calcThresBig, "upLeft",
                                                      isFirstCheck=True, upLeftBox=None, upRightBox=None, downLeftBox=None, offset=None,
                                                      isSizeCheck=True, totalBoard=totalBoard, totalBoardBox=totalBoardBox)

    upBoardResList = []
    upSizeResList = []
    if upRes != "error":
        for index, upBox in enumerate(upBoxes):
            if upBox is not None:
                upBoardRes = upLeftBoardColor.copy()
                cv.drawContours(upBoardRes, [np.array(upBox)], -1, colorGreen, 3)
                centerX, centerY = upLeftBoard.shape[1] // 2, upLeftBoard.shape[0] // 2
                cv.putText(upBoardRes, "{}".format(index + 1), (centerX - 8, centerY), cv.FONT_HERSHEY_COMPLEX, 10, colorBlue, 5)
                image_show("upBoardRes", upBoardRes)
                upBoardResList.append(upBoardRes)
                upSizeResList.append(upSizes[index])
        return "ok", upSizeResList, upBoardResList, upLeftBoardColor
    else:
        return "error", "内板识别出错", None, upLeftBoardColor


def get_boxes_4p(image, width, height, calcThresBig, calcThresSmall, totalBoardBox, totalBoard, upLeftOffset, upRightOffset,
                 downRightOffset, downLeftOffset, isFirstBoard):
    """
    4拼板获取内板位置信息
    :param image:
    :param width:
    :param height:
    :param calcThresBig:
    :param calcThresSmall:
    :param totalBoardBox:
    :param totalBoard:
    :param upLeftOffset:
    :param upRightOffset:
    :param downRightOffset:
    :param downLeftOffset:
    :param isFirstBoard:
    :return:
    """
    w, h = totalBoardBox[1]
    widthHalf = int(w / 2)
    heightHalf = int(h / 2)
    jointLineMask1 = np.ones(image.shape, dtype=np.uint8) * 255
    # 竖着进板的填充
    jointLineMask1[:, cp.middleJointPos - jointLineExtend:cp.middleJointPos + jointLineExtend] = 0
    # 横着进板的填充
    # jointLineMask1[cp.middleJointPos - jointLineExtend:cp.middleJointPos + jointLineExtend,:] = 0
    jointLineMaskNoAngle1, _ = get_board_without_angle(jointLineMask1, totalBoardBox)

    jointLineMask2 = np.zeros(image.shape, dtype=np.uint8)
    # 竖着进板的填充
    jointLineMask2[:, cp.middleJointPos02 - jointLineExtend:cp.middleJointPos02 + jointLineExtend] = 255
    # 横着进板的填充
    # jointLineMask2[cp.middleJointPos - jointLineExtend:cp.middleJointPos + jointLineExtend,:] = 255
    jointLineMaskNoAngle2, _ = get_board_without_angle(jointLineMask2, totalBoardBox)
    cv.destroyAllWindows()
    image_show("TotalBoard", totalBoard)

    upLeftBoard = totalBoard.copy()[:int(heightHalf + upDownSlice4p), :int(widthHalf + leftRightSlice4p)]
    upLeftJointLine1 = jointLineMaskNoAngle1.copy()[:int(heightHalf + upDownSlice4p), :int(widthHalf + leftRightSlice4p)]
    upLeftJointLine2 = jointLineMaskNoAngle2.copy()[:int(heightHalf + upDownSlice4p), :int(widthHalf + leftRightSlice4p)]

    upRightBoard = totalBoard.copy()[:int(heightHalf + upDownSlice4p), int(widthHalf - leftRightSlice4p):]
    upRightJointLine1 = jointLineMaskNoAngle1.copy()[:int(heightHalf + upDownSlice4p), int(widthHalf - leftRightSlice4p):]
    upRightJointLine2 = jointLineMaskNoAngle2.copy()[:int(heightHalf + upDownSlice4p), int(widthHalf - leftRightSlice4p):]

    downLeftBoard = totalBoard.copy()[int(heightHalf - upDownSlice4p):, :int(widthHalf + leftRightSlice4p)]
    downLeftJointLine1 = jointLineMaskNoAngle1.copy()[int(heightHalf - upDownSlice4p):, :int(widthHalf + leftRightSlice4p)]
    downLeftJointLine2 = jointLineMaskNoAngle2.copy()[int(heightHalf - upDownSlice4p):, :int(widthHalf + leftRightSlice4p)]

    downRightBoard = totalBoard.copy()[int(heightHalf - upDownSlice4p):, int(widthHalf - leftRightSlice4p):]
    downRightJointLine1 = jointLineMaskNoAngle1.copy()[int(heightHalf - upDownSlice4p):, int(widthHalf - leftRightSlice4p):]
    downRightJointLine2 = jointLineMaskNoAngle2.copy()[int(heightHalf - upDownSlice4p):, int(widthHalf - leftRightSlice4p):]

    res1, info1, upLeftBox = get_inner_board_info_4p(upLeftBoard, upLeftJointLine1, upLeftJointLine2, width, height, calcThresBig, calcThresSmall,
                                                     "upLeft", isFirstCheck=isFirstBoard, upLeftBox=None, upRightBox=None, downLeftBox=None,
                                                     offset=upLeftOffset, isSizeCheck=False, totalBoard=totalBoard, totalBoardBox=totalBoardBox)
    if res1 != "ok":
        return False, "左上框识别失败,识别信息: {}".format(info1), [upLeftBox, None, None, None]

    res2, info2, upRightBox = get_inner_board_info_4p(upRightBoard, upRightJointLine1, upRightJointLine2, width, height, calcThresBig,
                                                      calcThresSmall, "upRight", isFirstCheck=isFirstBoard, upLeftBox=upLeftBox,
                                                      upRightBox=None, downLeftBox=None, offset=upRightOffset, isSizeCheck=False,
                                                      totalBoard=totalBoard, totalBoardBox=totalBoardBox)
    if res2 != "ok":
        return False, "右上框识别失败,识别信息: {}".format(info2), [upLeftBox, upRightBox, None, None]

    res3, info3, downLeftBox = get_inner_board_info_4p(downLeftBoard, downLeftJointLine1, downLeftJointLine2, width, height, calcThresBig,
                                                       calcThresSmall, "downLeft", isFirstCheck=isFirstBoard, upLeftBox=upLeftBox,
                                                       upRightBox=upRightBox, downLeftBox=None, offset=downLeftOffset, isSizeCheck=False,
                                                       totalBoard=totalBoard, totalBoardBox=totalBoardBox)
    if res3 != "ok":
        return False, "左下框识别失败,识别信息: {}".format(info3), [upLeftBox, upRightBox, downLeftBox, None]

    res4, info4, downRightBox = get_inner_board_info_4p(downRightBoard, downRightJointLine1, downRightJointLine2, width, height, calcThresBig,
                                                        calcThresSmall, "downRight", isFirstCheck=isFirstBoard, upLeftBox=upLeftBox,
                                                        upRightBox=upRightBox, downLeftBox=downLeftBox, offset=downRightOffset, isSizeCheck=False,
                                                        totalBoard=totalBoard, totalBoardBox=totalBoardBox)
    if res4 != "ok":
        return False, "右下框识别失败,识别信息: {}".format(info4), [upLeftBox, upRightBox, downLeftBox, downRightBox]

    upRightBoxPoints = [(p[0] + widthHalf - leftRightSlice4p, p[1]) for p in upRightBox]
    downLeftBoxPoints = [(p[0], p[1] + heightHalf - upDownSlice4p) for p in downLeftBox]
    downRightBoxPoints = [(p[0] + widthHalf - leftRightSlice4p, p[1] + heightHalf - upDownSlice4p) for p in downRightBox]
    upRightBox = upRightBoxPoints
    downLeftBox = downLeftBoxPoints
    downRightBox = downRightBoxPoints
    totalBoardColor = cv.cvtColor(totalBoard.copy(), cv.COLOR_GRAY2BGR)
    cv.drawContours(totalBoardColor, [np.array(upLeftBox), np.array(upRightBox), np.array(downLeftBox), np.array(downRightBox)], -1, (0, 255, 0), 3)
    image_show("FourBoxes", totalBoardColor)
    return True, "1,2,3,4框全部识别成功!", [upLeftBox, upRightBox, downLeftBox, downRightBox]


def get_lines_with_boxes_4p(image, totalBoardBox, totalBoardThresWithAngle, boxes, transMtx, topRemain, leftRemain,
                            bottomRemain, rightRemain, totalBoardOffset):
    """
    4拼板获取切线
    :param image:
    :param totalBoard:
    :param totalBoardBox:
    :param totalBoardThresWithAngle:
    :param boxes:
    :param transMtx:
    :param topRemain:
    :param leftRemain:
    :param bottomRemain:
    :param rightRemain:
    :param totalBoardOffset:
    :return:
    """
    upLeftBox, upRightBox, downLeftBox, downRightBox = boxes
    upLeftLeftTop, upLeftRightTop, upLeftRightBottom, upLeftLeftBottom = upLeftBox
    upRightLeftTop, upRightRightTop, upRightRightBottom, upRightLeftBottom = upRightBox
    downLeftLeftTop, downLeftRightTop, downLeftRightBottom, downLeftLeftBottom = downLeftBox
    downRightLeftTop, downRightRightTop, downRightRightBottom, downRightLeftBottom = downRightBox

    leftCutLineK = get_linear_fit_k_vertical(np.array([upLeftLeftTop, upLeftLeftBottom, downLeftLeftTop, downLeftLeftBottom]))
    if leftCutLineK is None:
        leftCutLineB = min(upLeftLeftTop[0], upLeftLeftBottom[0], downLeftLeftTop[0], downLeftLeftBottom[0]) - leftRemain
    else:
        upLeftLeftTopB = upLeftLeftTop[1] - (upLeftLeftTop[0] - leftRemain) * leftCutLineK
        upLeftLeftBottomB = upLeftLeftBottom[1] - (upLeftLeftBottom[0] - leftRemain) * leftCutLineK
        downLeftLeftTopB = downLeftLeftTop[1] - (downLeftLeftTop[0] - leftRemain) * leftCutLineK
        downLeftLeftBottomB = downLeftLeftBottom[1] - (downLeftLeftBottom[0] - leftRemain) * leftCutLineK

        if leftCutLineK > 0:
            leftCutLineB = max(upLeftLeftTopB, upLeftLeftBottomB, downLeftLeftBottomB, downLeftLeftTopB)
        else:
            leftCutLineB = min(upLeftLeftTopB, upLeftLeftBottomB, downLeftLeftBottomB, downLeftLeftTopB)

    rightCutLineK = get_linear_fit_k_vertical(np.array([upRightRightTop, upRightRightBottom, downRightRightTop, downRightRightBottom]))
    if rightCutLineK is None:
        rightCutLineB = max(upRightRightTop[0], upRightRightBottom[0], downRightRightTop[0], downRightRightBottom[0]) + rightRemain
    else:
        upRightRightTopB = upRightRightTop[1] - (upRightRightTop[0] + rightRemain) * rightCutLineK
        upRightRightBottomB = upRightRightBottom[1] - (upRightRightBottom[0] + rightRemain) * rightCutLineK
        downRightRightTopB = downRightRightTop[1] - (downRightRightTop[0] + rightRemain) * rightCutLineK
        downRightRightBottomB = downRightRightBottom[1] - (downRightRightBottom[0] + rightRemain) * rightCutLineK

        if rightCutLineK > 0:
            rightCutLineB = min(upRightRightTopB, upRightRightBottomB, downRightRightTopB, downRightRightBottomB)
        else:
            rightCutLineB = max(upRightRightTopB, upRightRightBottomB, downRightRightTopB, downRightRightBottomB)

    topCutLineK, _ = get_linear_fit_k_and_b_horizontal(np.array([upLeftLeftTop, upLeftRightTop, upRightLeftTop, upRightRightTop]))
    if topCutLineK is None:
        return False, None, None, None, None, None
    else:
        upLeftLeftTopB = upLeftLeftTop[1] - topRemain - upLeftLeftTop[0] * topCutLineK
        upLeftRightTopB = upLeftRightTop[1] - topRemain - upLeftRightTop[0] * topCutLineK
        upRightLeftTopB = upRightLeftTop[1] - topRemain - upRightLeftTop[0] * topCutLineK
        upRightRightTopB = upRightRightTop[1] - topRemain - upRightRightTop[0] * topCutLineK
        topCutLineB = min(upLeftLeftTopB, upLeftRightTopB, upRightLeftTopB, upRightRightTopB)

    bottomCutLineK, _ = get_linear_fit_k_and_b_horizontal(
        np.array([downLeftLeftBottom, downLeftRightBottom, downRightLeftBottom, downRightRightBottom]))
    if bottomCutLineK is None:
        return False, None, None, None, None, None
    else:
        downLeftLeftBottomB = downLeftLeftBottom[1] + bottomRemain - downLeftLeftBottom[0] * bottomCutLineK
        downLeftRightBottomB = downLeftRightBottom[1] + bottomRemain - downLeftRightBottom[0] * bottomCutLineK
        downRightLeftBottomB = downRightLeftBottom[1] + bottomRemain - downRightLeftBottom[0] * bottomCutLineK
        downRightRightBottomB = downRightRightBottom[1] + bottomRemain - downRightRightBottom[0] * bottomCutLineK

        bottomCutLineB = max(downLeftLeftBottomB, downLeftRightBottomB, downRightLeftBottomB, downRightRightBottomB)

    horizontalMiddleLineK, horizontalMiddleLineB = get_horizontal_middle_line_4p([upLeftLeftBottom, upLeftRightBottom,
                                                                                  upRightLeftBottom, upRightRightBottom],
                                                                                 [downLeftLeftTop, downLeftRightTop,
                                                                                  downRightLeftTop, downRightRightTop])
    verticalMiddleLineUpK, verticalMiddleLineUpB = get_vertical_middle_cut_line_4p([upLeftRightTop, upLeftRightBottom],
                                                                                   [upRightLeftTop, upRightLeftBottom])
    verticalMiddleLineDownK, verticalMiddleLineDownB = get_vertical_middle_cut_line_4p([downLeftRightTop, downLeftRightBottom],
                                                                                       [downRightLeftTop, downRightLeftBottom])

    rotatedCenter, (w, h), rotatedAngle = totalBoardBox
    # 物料区域的四个顶点
    boardLeftTop = [0, 0]
    boardRightTop = [w, 0]
    boardRightBottom = [w, h]
    boardLeftBottom = [0, h]

    findEdgeExtend = int(7 * cp.mm2pix)
    totalBoardExtendForFindEdge, _ = get_board_without_angle(image, totalBoardBox, findEdgeExtend)
    totalBoardThresForFindEdge, _ = get_board_without_angle(totalBoardThresWithAngle, totalBoardBox, findEdgeExtend)

    if topRemain == 0:
        topLineK, topLineB = find_first_edge_line(totalBoardExtendForFindEdge, totalBoardThresForFindEdge, findEdgeExtend)
        if topLineK is not None:
            topCutLineK, topCutLineB = topLineK, topLineB
        else:
            topCutLineK, topCutLineB = get_line_k_and_b(boardLeftTop, boardRightTop)

    if bottomRemain == 0:
        bottomLineK, bottomLineB = find_third_edge_line(totalBoardExtendForFindEdge, totalBoardThresForFindEdge, findEdgeExtend)
        if bottomLineK is not None:
            bottomCutLineK, bottomCutLineB = bottomLineK, bottomLineB
        else:
            bottomCutLineK, bottomCutLineB = get_line_k_and_b(boardLeftBottom, boardRightBottom)

    if leftRemain == 0:
        leftCutLineK, leftCutLineB = get_line_k_and_b(boardLeftBottom, boardLeftTop)

    if rightRemain == 0:
        rightCutLineK, rightCutLineB = get_line_k_and_b(boardRightTop, boardRightBottom)

    leftTopCross = get_two_lines_intersection(topCutLineK, topCutLineB, leftCutLineK, leftCutLineB)
    rightTopCross = get_two_lines_intersection(topCutLineK, topCutLineB, rightCutLineK, rightCutLineB)
    leftBottomCross = get_two_lines_intersection(bottomCutLineK, bottomCutLineB, leftCutLineK, leftCutLineB)
    rightBottomCross = get_two_lines_intersection(bottomCutLineK, bottomCutLineB, rightCutLineK, rightCutLineB)
    if leftTopCross[0] is None or rightTopCross[0] is None or leftBottomCross[0] is None or rightBottomCross[0] is None:
        return False, None, None, None, None, None

    extend13 = int(cp.lineExtend13 * cp.mm2pix)  # 1.3刀的延长切线
    extend24 = int(cp.lineExtend24 * cp.mm2pix)  # 2.4刀的延长切线
    topCutLeftPoint = [-extend13, topCutLineK * (-extend13) + topCutLineB]
    topCutRightPoint = [extend13 + w, topCutLineK * (extend13 + w) + topCutLineB]
    bottomCutLeftPoint = [-extend13, bottomCutLineK * (-extend13) + bottomCutLineB]
    bottomCutRightPoint = [w + extend13, bottomCutLineK * (w + extend13) + bottomCutLineB]
    if leftCutLineK is None:
        leftCutLineTop = [leftCutLineB, leftTopCross[1] - extend24]
        leftCutLineBottom = [leftCutLineB, leftBottomCross[1] + extend24]
    elif leftCutLineK != 0:
        leftCutLineTop = [(leftTopCross[1] - extend24 - leftCutLineB) / leftCutLineK, leftTopCross[1] - extend24]
        leftCutLineBottom = [(leftBottomCross[1] + extend24 - leftCutLineB) / leftCutLineK, leftBottomCross[1] + extend24]
    else:
        cv.destroyAllWindows()
        return False, None, None, None, None, None

    if rightCutLineK is None:
        rightCutLineTop = [rightCutLineB, rightTopCross[1] - extend24]
        rightCutLineBottom = [rightCutLineB, rightBottomCross[1] + extend24]
    elif rightCutLineK != 0:
        rightCutLineTop = [(rightTopCross[1] - extend24 - rightCutLineB) / rightCutLineK, rightTopCross[1] - extend24]
        rightCutLineBottom = [(rightBottomCross[1] + extend24 - rightCutLineB) / rightCutLineK, rightBottomCross[1] + extend24]
    else:
        cv.destroyAllWindows()
        return False, None, None, None, None, None

    horMidLeftCross = get_two_lines_intersection(leftCutLineK, leftCutLineB, horizontalMiddleLineK, horizontalMiddleLineB)
    horMidRightCross = get_two_lines_intersection(rightCutLineK, rightCutLineB, horizontalMiddleLineK, horizontalMiddleLineB)
    verUpTopCross = get_two_lines_intersection(verticalMiddleLineUpK, verticalMiddleLineUpB, topCutLineK, topCutLineB)
    verUpMiddleCross = get_two_lines_intersection(verticalMiddleLineUpK, verticalMiddleLineUpB, horizontalMiddleLineK, horizontalMiddleLineB)
    verDownMiddleCross = get_two_lines_intersection(verticalMiddleLineDownK, verticalMiddleLineDownB, horizontalMiddleLineK, horizontalMiddleLineB)
    verDownBottomCross = get_two_lines_intersection(verticalMiddleLineDownK, verticalMiddleLineDownB, bottomCutLineK, bottomCutLineB)

    M = cv.getRotationMatrix2D(rotatedCenter, -rotatedAngle, 1)
    centerOffset = totalBoardOffset

    # 定位到大图上去
    boardLeftTopBig = np.dot(M, [boardLeftTop[0] + centerOffset[0], boardLeftTop[1] + centerOffset[1], 1])
    boardRightTopBig = np.dot(M, [boardRightTop[0] + centerOffset[0], boardRightTop[1] + centerOffset[1], 1])
    boardRightBottomBig = np.dot(M, [boardRightBottom[0] + centerOffset[0], boardRightBottom[1] + centerOffset[1], 1])
    boardLeftBottomBig = np.dot(M, [boardLeftBottom[0] + centerOffset[0], boardLeftBottom[1] + centerOffset[1], 1])

    topCutLeftPointBig = np.dot(M, [topCutLeftPoint[0] + centerOffset[0], topCutLeftPoint[1] + centerOffset[1], 1])
    topCutRightPointBig = np.dot(M, [topCutRightPoint[0] + centerOffset[0], topCutRightPoint[1] + centerOffset[1], 1])

    bottomCutRightPointBig = np.dot(M, [bottomCutRightPoint[0] + centerOffset[0], bottomCutRightPoint[1] + centerOffset[1], 1])

    bottomCutLeftPointBig = np.dot(M, [bottomCutLeftPoint[0] + centerOffset[0], bottomCutLeftPoint[1] + centerOffset[1], 1])

    leftCutLineBottomBig = np.dot(M, [leftCutLineBottom[0] + centerOffset[0], leftCutLineBottom[1] + centerOffset[1], 1])

    leftCutLineTopBig = np.dot(M, [leftCutLineTop[0] + centerOffset[0], leftCutLineTop[1] + centerOffset[1], 1])
    rightCutLineTopBig = np.dot(M, [rightCutLineTop[0] + centerOffset[0], rightCutLineTop[1] + centerOffset[1], 1])
    rightCutLineBottomBig = np.dot(M, [rightCutLineBottom[0] + centerOffset[0], rightCutLineBottom[1] + centerOffset[1], 1])
    horMidLeftCrossBig = np.dot(M, [horMidLeftCross[0] + centerOffset[0], horMidLeftCross[1] + centerOffset[1], 1])
    horMidRightCrossBig = np.dot(M, [horMidRightCross[0] + centerOffset[0], horMidRightCross[1] + centerOffset[1], 1])

    verUpTopCrossBig = np.dot(M, [verUpTopCross[0] + centerOffset[0], verUpTopCross[1] + centerOffset[1], 1])
    verUpMiddleCrossBig = np.dot(M, [verUpMiddleCross[0] + centerOffset[0], verUpMiddleCross[1] + centerOffset[1], 1])
    verDownMiddleCrossBig = np.dot(M, [verDownMiddleCross[0] + centerOffset[0], verDownMiddleCross[1] + centerOffset[1], 1])
    verDownBottomCrossBig = np.dot(M, [verDownBottomCross[0] + centerOffset[0], verDownBottomCross[1] + centerOffset[1], 1])

    upLeftBoxBig = [np.dot(M, [p[0] + centerOffset[0], p[1] + centerOffset[1], 1]) for p in upLeftBox]
    upRightBoxBig = [np.dot(M, [p[0] + centerOffset[0], p[1] + centerOffset[1], 1]) for p in upRightBox]
    downLeftBoxBig = [np.dot(M, [p[0] + centerOffset[0], p[1] + centerOffset[1], 1]) for p in downLeftBox]
    downRightBoxBig = [np.dot(M, [p[0] + centerOffset[0], p[1] + centerOffset[1], 1]) for p in downRightBox]

    imageColor = cv.cvtColor(image, cv.COLOR_GRAY2BGR)

    # 画出四个内框
    for index, p in enumerate(upLeftBoxBig):
        p1 = (int(p[0]), int(p[1]))
        p2 = upLeftBoxBig[(index + 1) % len(upLeftBoxBig)]
        p2 = int(p2[0]), int(p2[1])
        cv.line(imageColor, p1, p2, colorGreen, 3)

    for index, p in enumerate(upRightBoxBig):
        p1 = (int(p[0]), int(p[1]))
        p2 = upRightBoxBig[(index + 1) % len(upRightBoxBig)]
        p2 = int(p2[0]), int(p2[1])
        cv.line(imageColor, p1, p2, colorGreen, 3)

    for index, p in enumerate(downLeftBoxBig):
        p1 = (int(p[0]), int(p[1]))
        p2 = downLeftBoxBig[(index + 1) % len(downLeftBoxBig)]
        p2 = int(p2[0]), int(p2[1])
        cv.line(imageColor, p1, p2, colorGreen, 3)

    for index, p in enumerate(downRightBoxBig):
        p1 = (int(p[0]), int(p[1]))
        p2 = downRightBoxBig[(index + 1) % len(downRightBoxBig)]
        p2 = int(p2[0]), int(p2[1])
        cv.line(imageColor, p1, p2, colorGreen, 3)

    # 画出上,下,左,右,还有中线.
    cv.line(imageColor, (int(topCutLeftPointBig[0]), int(topCutLeftPointBig[1])),
            (int(topCutRightPointBig[0]), int(topCutRightPointBig[1])), colorRed, 3)
    cv.putText(imageColor, '1', (int((topCutLeftPointBig[0] + topCutRightPointBig[0]) / 2),
                                 int((topCutLeftPointBig[1] + topCutRightPointBig[1]) / 2) - 10),
               cv.FONT_HERSHEY_COMPLEX, 4, colorRed, 5)
    cv.line(imageColor, (int(bottomCutRightPointBig[0]), int(bottomCutRightPointBig[1])),
            (int(bottomCutLeftPointBig[0]), int(bottomCutLeftPointBig[1])), colorRed, 3)
    cv.putText(imageColor, '3', (int((bottomCutRightPointBig[0] + bottomCutLeftPointBig[0]) / 2),
                                 int((bottomCutRightPointBig[1] + bottomCutLeftPointBig[1]) / 2) + 80),
               cv.FONT_HERSHEY_COMPLEX, 4, colorRed, 5)

    cv.line(imageColor, (int(leftCutLineBottomBig[0]), int(leftCutLineBottomBig[1])),
            (int(leftCutLineTopBig[0]), int(leftCutLineTopBig[1])), colorRed, 3)
    cv.putText(imageColor, '4', (int((leftCutLineBottomBig[0] + leftCutLineTopBig[0]) / 2) - 80,
                                 int((leftCutLineBottomBig[1] + leftCutLineTopBig[1]) / 2)),
               cv.FONT_HERSHEY_COMPLEX, 4, colorRed, 5)
    cv.line(imageColor, (int(rightCutLineTopBig[0]), int(rightCutLineTopBig[1])),
            (int(rightCutLineBottomBig[0]), int(rightCutLineBottomBig[1])), colorRed, 3)
    cv.putText(imageColor, '2', (int((rightCutLineTopBig[0] + rightCutLineBottomBig[0]) / 2) + 10,
                                 int((rightCutLineTopBig[1] + rightCutLineBottomBig[1]) / 2)),
               cv.FONT_HERSHEY_COMPLEX, 4, colorRed, 5)

    cv.line(imageColor, (int(horMidLeftCrossBig[0]), int(horMidLeftCrossBig[1])),
            (int(horMidRightCrossBig[0]), int(horMidRightCrossBig[1])), colorRed, 3)

    cv.line(imageColor, (int(verUpTopCrossBig[0]), int(verUpTopCrossBig[1])),
            (int(verUpMiddleCrossBig[0]), int(verUpMiddleCrossBig[1])), colorRed, 3)
    cv.line(imageColor, (int(verDownMiddleCrossBig[0]), int(verDownMiddleCrossBig[1])),
            (int(verDownBottomCrossBig[0]), int(verDownBottomCrossBig[1])), colorRed, 3)

    boardLeftTopRobot = pix_pos_to_robot(boardLeftTopBig, transMtx)
    boardRightTopRobot = pix_pos_to_robot(boardRightTopBig, transMtx)
    boardRightBottomRobot = pix_pos_to_robot(boardRightBottomBig, transMtx)
    boardLeftBottomRobot = pix_pos_to_robot(boardLeftBottomBig, transMtx)
    topCutLeftPointRobot = pix_pos_to_robot(topCutLeftPointBig, transMtx)

    topCutRightPointRobot = pix_pos_to_robot(topCutRightPointBig, transMtx)
    bottomCutRightPointRobot = pix_pos_to_robot(bottomCutRightPointBig, transMtx)
    bottomCutLeftPointRobot = pix_pos_to_robot(bottomCutLeftPointBig, transMtx)
    leftCutLineBottomRobot = pix_pos_to_robot(leftCutLineBottomBig, transMtx)
    leftCutLineTopRobot = pix_pos_to_robot(leftCutLineTopBig, transMtx)
    rightCutLineTopRobot = pix_pos_to_robot(rightCutLineTopBig, transMtx)
    rightCutLineBottomRobot = pix_pos_to_robot(rightCutLineBottomBig, transMtx)
    horMidLeftCrossRobot = pix_pos_to_robot(horMidLeftCrossBig, transMtx)
    horMidRightCrossRobot = pix_pos_to_robot(horMidRightCrossBig, transMtx)
    verUpTopCrossRobot = pix_pos_to_robot(verUpTopCrossBig, transMtx)
    verUpMiddleCrossRobot = pix_pos_to_robot(verUpMiddleCrossBig, transMtx)
    verDownMiddleCrossRobot = pix_pos_to_robot(verDownMiddleCrossBig, transMtx)
    verDownBottomCrossRobot = pix_pos_to_robot(verDownBottomCrossBig, transMtx)

    # 计算裁切面积和切割的长度
    cutDisTotal = 0
    cutAreaTotal = 0
    if topRemain != 0:
        cutDis = get_two_point_distance(topCutLeftPointRobot, topCutRightPointRobot)
        area = cutDis * (get_two_line_distance([topCutLeftPointRobot, topCutRightPointRobot], [boardLeftTopRobot, boardRightTopRobot]))
        cutDisTotal += cutDis
        cutAreaTotal += area
    if leftRemain != 0:
        cutDis = get_two_point_distance(leftCutLineBottomRobot, leftCutLineTopRobot)
        area = cutDis * (get_two_line_distance([leftCutLineTopRobot, leftCutLineBottomRobot], [boardLeftTopRobot, boardLeftBottomRobot]))
        cutDisTotal += cutDis
        cutAreaTotal += area
    if bottomRemain != 0:
        cutDis = get_two_point_distance(bottomCutLeftPointRobot, bottomCutRightPointRobot)
        area = cutDis * (get_two_line_distance([bottomCutLeftPointRobot, bottomCutRightPointRobot], [boardLeftBottomRobot, boardRightBottomRobot]))
        cutDisTotal += cutDis
        cutAreaTotal += area
    if rightRemain != 0:
        cutDis = get_two_point_distance(rightCutLineTopRobot, rightCutLineBottomRobot)
        area = cutDis * (get_two_line_distance([rightCutLineTopRobot, rightCutLineBottomRobot], [boardRightTopRobot, boardRightBottomRobot]))
        cutDisTotal += cutDis
        cutAreaTotal += area

    imageResult, _ = get_board_without_angle(imageColor, totalBoardBox, extend=80)
    image_show("ResultImage", imageResult)

    # 计算板大板的板长
    firstLengthBig, secondLengthBig = get_board_length_4p_big([topCutLeftPointRobot, topCutRightPointRobot],
                                                              [horMidLeftCrossRobot, horMidRightCrossRobot],
                                                              [bottomCutLeftPointRobot, bottomCutRightPointRobot])
    # 计算第一块小板的板长
    firstLengthSmall, secondLengthSmall = get_board_length_4p_small([leftCutLineTopRobot, leftCutLineBottomRobot],
                                                                    [verUpTopCrossRobot, verUpMiddleCrossRobot],
                                                                    [rightCutLineTopRobot, rightCutLineBottomRobot])
    # 计算第二块小板的板长
    thirdLengthSmall, forthLengthSmall = get_board_length_4p_small([leftCutLineTopRobot, leftCutLineBottomRobot],
                                                                   [verDownMiddleCrossRobot, verDownBottomCrossRobot],
                                                                   [rightCutLineTopRobot, rightCutLineBottomRobot])

    topMiddleAngle = get_two_line_angle([horMidRightCrossRobot, horMidLeftCrossRobot], [topCutRightPointRobot, topCutLeftPointRobot])
    bottomMiddleAngle = get_two_line_angle([horMidRightCrossRobot, horMidLeftCrossRobot], [bottomCutRightPointRobot, bottomCutLeftPointRobot])
    leftMiddleUp = get_two_line_angle([verUpMiddleCrossRobot, verUpTopCrossRobot], [leftCutLineBottomRobot, leftCutLineTopRobot])
    rightMiddleUp = get_two_line_angle([verUpMiddleCrossRobot, verUpTopCrossRobot], [rightCutLineBottomRobot, rightCutLineTopRobot])
    leftMiddleDown = get_two_line_angle([verDownBottomCrossRobot, verDownMiddleCrossRobot], [leftCutLineBottomRobot, leftCutLineTopRobot])
    rightMiddleDown = get_two_line_angle([verDownBottomCrossRobot, verDownMiddleCrossRobot], [rightCutLineBottomRobot, rightCutLineTopRobot])

    # 计算中缝的垂线
    horMiddleVerK, horMiddleVerB = get_hor_middle_vertical_line_k_and_b(horMidLeftCrossRobot, horMidRightCrossRobot)
    topCutLineK, topCutLineB = get_line_k_and_b(topCutLeftPointRobot, topCutRightPointRobot)
    bottomCutLineK, bottomCutLineB = get_line_k_and_b(bottomCutLeftPointRobot, bottomCutRightPointRobot)
    # 计算中缝的垂线和垂直的线的四个交点,从上到下
    intersectionUp = get_two_lines_intersection(horMiddleVerK, horMiddleVerB, topCutLineK, topCutLineB)
    intersectionDown = get_two_lines_intersection(horMiddleVerK, horMiddleVerB, bottomCutLineK, bottomCutLineB)

    # 再计算角度: 水平移动到铡刀平行的角度.就是个参照物.如果终检本身有角度,那就再算.目标是将板子移动到和大铡刀平齐
    horVerAngleUp = get_two_line_angle([intersectionDown, intersectionUp], [verUpMiddleCrossRobot, verUpTopCrossRobot])
    horVerAngleDown = get_two_line_angle([intersectionDown, intersectionUp], [verDownBottomCrossRobot, verDownMiddleCrossRobot])
    # 第二刀作为小铡刀第一边检测的情况
    # angleList = [topMiddleAngle, bottomMiddleAngle, leftMiddleUp, rightMiddleUp, horVerAngleUp, leftMiddleDown, rightMiddleDown, horVerAngleDown]
    # 第四刀作为小铡刀第一边检测的情况
    angleList = [topMiddleAngle, bottomMiddleAngle, rightMiddleUp, leftMiddleUp, horVerAngleUp, rightMiddleDown, leftMiddleDown, horVerAngleDown]
    boardLenthList = [firstLengthBig, secondLengthBig, firstLengthSmall, secondLengthSmall, thirdLengthSmall, forthLengthSmall]
    isFirstCut = True if topRemain != 0 else False
    isThirdCut = True if bottomRemain != 0 else False
    cutWidth = round(get_two_point_distance(leftTopCross, rightTopCross) / cp.mm2pix, 2)
    cutLines = [topCutLeftPointRobot, topCutRightPointRobot, bottomCutRightPointRobot, bottomCutLeftPointRobot,
                leftCutLineBottomRobot, leftCutLineTopRobot, rightCutLineTopRobot, rightCutLineBottomRobot, horMidLeftCrossRobot,
                horMidRightCrossRobot, verUpTopCrossRobot, verUpMiddleCrossRobot, verDownMiddleCrossRobot, verDownBottomCrossRobot]
    return cutLines, imageResult, boardLenthList, angleList, cutDisTotal, cutAreaTotal, isFirstCut, isThirdCut, cutWidth


def get_line_offset_4p(boxes, totalBoard, totalBoardBox):
    """
    获取4pin板4个内框的位置信息.
    :param boxes:
    :param totalBoard:
    :param totalBoardBox:
    :return:
    """
    upLeftBox, upRightBox, downLeftBox, downRightBox = boxes
    w, h = totalBoardBox[1]
    heightHalf = int(h / 2)
    widthHalf = int(w / 2)
    upLeftBoard = totalBoard.copy()[:int(heightHalf + upDownSlice4p), :int(widthHalf + leftRightSlice4p)]

    upH, upW = upLeftBoard.shape[:2]
    p1 = (0, 0)
    p2 = (upW, 0)
    p3 = (upW, upH)
    p4 = (0, upH)
    p5, p6, p7, p8 = upLeftBox
    innerLine1, innerLine2, innerLine3, innerLine4 = [(p5, p6), (p6, p7), (p7, p8), (p8, p5)]
    outterLine1, outterLine2, outterLine3, outterLine4 = [(p1, p2), (p2, p3), (p3, p4), (p4, p1)]
    offsetTop = get_two_line_distance(innerLine1, outterLine1)
    offsetRight = get_two_line_distance(innerLine2, outterLine2)
    offsetBottom = get_two_line_distance(innerLine3, outterLine3)
    offsetLeft = get_two_line_distance(innerLine4, outterLine4)
    upLeftOffset = [int(offsetTop), int(offsetRight), int(offsetBottom), int(offsetLeft)]

    # 计算第二个框的坐标
    p1 = (widthHalf - leftRightSlice4p, 0)
    p2 = (w, 0)
    p3 = (w, upH)
    p4 = (0, upH)
    p5, p6, p7, p8 = upRightBox
    innerLine1, innerLine2, innerLine3, innerLine4 = [(p5, p6), (p6, p7), (p7, p8), (p8, p5)]
    outterLine1, outterLine2, outterLine3, outterLine4 = [(p1, p2), (p2, p3), (p3, p4), (p4, p1)]
    offsetTop = get_two_line_distance(innerLine1, outterLine1)
    offsetRight = get_two_line_distance(innerLine2, outterLine2)
    offsetBottom = get_two_line_distance(innerLine3, outterLine3)
    offsetLeft = get_two_line_distance(innerLine4, outterLine4)
    upRightOffset = [int(offsetTop), int(offsetRight), int(offsetBottom), int(offsetLeft)]

    # 计算第三个框的坐标
    p1 = (0, heightHalf - upDownSlice4p)
    p2 = (widthHalf + leftRightSlice4p, heightHalf - upDownSlice4p)
    p3 = (widthHalf + leftRightSlice4p, h)
    p4 = (0, h)
    p5, p6, p7, p8 = downLeftBox
    innerLine1, innerLine2, innerLine3, innerLine4 = [(p5, p6), (p6, p7), (p7, p8), (p8, p5)]
    outterLine1, outterLine2, outterLine3, outterLine4 = [(p1, p2), (p2, p3), (p3, p4), (p4, p1)]
    offsetTop = get_two_line_distance(innerLine1, outterLine1)
    offsetRight = get_two_line_distance(innerLine2, outterLine2)
    offsetBottom = get_two_line_distance(innerLine3, outterLine3)
    offsetLeft = get_two_line_distance(innerLine4, outterLine4)
    downLeftOffset = [int(offsetTop), int(offsetRight), int(offsetBottom), int(offsetLeft)]

    # 计算第四个框的坐标
    p1 = (widthHalf - leftRightSlice4p, heightHalf - upDownSlice4p)
    p2 = (w, heightHalf - upDownSlice4p)
    p3 = (w, h)
    p4 = (widthHalf - leftRightSlice4p, h)

    p5, p6, p7, p8 = downRightBox
    innerLine1, innerLine2, innerLine3, innerLine4 = [(p5, p6), (p6, p7), (p7, p8), (p8, p5)]
    outterLine1, outterLine2, outterLine3, outterLine4 = [(p1, p2), (p2, p3), (p3, p4), (p4, p1)]
    offsetTop = get_two_line_distance(innerLine1, outterLine1)
    offsetRight = get_two_line_distance(innerLine2, outterLine2)
    offsetBottom = get_two_line_distance(innerLine3, outterLine3)
    offsetLeft = get_two_line_distance(innerLine4, outterLine4)
    downRightOffset = [int(offsetTop), int(offsetRight), int(offsetBottom), int(offsetLeft)]
    return upLeftOffset, upRightOffset, downLeftOffset, downRightOffset


if __name__ == '__main__':
    filePath = r"F:\raw_2025\weiergao"
    res, data = db.get_line_cam_check_thres()
    totalHeightMax = data.get("totalHeightMax")
    totalHeightMin = data.get("totalHeightMin")
    boardBreak = False
    calcThresBig = 20
    calcThresSmall = 8
    res1, transMtxData = db.get_trans_mtx_data()
    # if res1 != "ok":
    #     errorInfo = "{},标定矩阵获取失败!".format(res1)
    #     print(errorInfo)
    # else:
    #     transMtx = transMtxData.get("mtx")

    transMtx = []
    if res != "ok":
        errorInfo = "in reload_trans_mtx() error: {}".format(transMtxData)
        print(errorInfo)
    else:
        transMtx = transMtxData.get("transMtx", [[1, 0, 1], [0, 1, 0]])
        # mtxRigth = transMtxData.get("mtxRight",[[1,0,1],[0,1,0]])
        # transMtx.append(mtxLeft)
        # transMtx.append(mtxRigth)

    jointNumber = "4"
    remainEdgeMm = [0, 15, 0, 15]
    topRemain, leftRemain, bottomRemain, rightRemain = [int(x * cp.mm2pix) for x in remainEdgeMm]
    result = create_image_test_dir(filePath)
    if not result.state:
        print(result.info)
        exit(0)
    filePath, fileNames, keepOkPath, keepOkResPath, keepFailPath, keepFirstSizeBestRes = result.data

    for index, fileName in enumerate(fileNames):
        fileName = str(fileName)
        filePathReal = os.path.join(filePath, fileName)
        box1Offset = box2Offset = box3Offset = box4Offset = [0, 0, 0, 0]
        isFirstBoard = False
        if jointNumber == "4":
            srcW, srcH, box1Offset, box2Offset, box3Offset, box4Offset = get_width_height_by_image_name_4p(fileName)
        else:
            srcW, srcH = get_width_and_height_by_image_name_6p(fileName)
        if srcW is None or srcH is None:
            print("*" * 10 + "第 {} 张图 ({}),图像名称错误,已跳过".format(index + 1, fileName))

        print("*" * 10 + "第 {} 张图 ({})".format(index + 1, fileName) + "*" * 10)
        calcStart = time.time()
        imageSrc = cv.imread(filePathReal, cv.IMREAD_GRAYSCALE)
        settings.showState = False
        totalBoardRes = check_total_board_is_ok(imageSrc, totalHeightMax, totalHeightMin, boardBreak, jointNumber)
        res, hintInfo, totalBoardBox, totalBoardNoAngle, totalBoardOffset, totalBoardThresWithAngle, totalBoardResWithAngle = totalBoardRes
        print("物料检测结果: {}, {}".format(res, hintInfo))
        if isFirstBoard:
            settings.showState = True
            resFirst, boardSizeList, boardResList, upLeftBoard = get_size_check_result_4p(imageSrc, srcW, srcH, calcThresBig, totalBoardBox,
                                                                                          totalBoardNoAngle)
            if resFirst != "error":
                sizeCheckResBest = boardResList[0]
                sizeCheckResBest = get_size_scale_image(sizeCheckResBest, sizeScale=4)
                cv.imwrite(os.path.join(keepFirstSizeBestRes, fileName), sizeCheckResBest)
        boxList4p = None
        settings.showState = False
        if jointNumber == "4":
            res, info, boxList4p = get_boxes_4p(imageSrc, srcW, srcH, calcThresBig, calcThresSmall, totalBoardBox, totalBoardNoAngle,
                                                box1Offset, box2Offset, box3Offset, box4Offset, isFirstBoard)

        settings.showState = True
        if res:
            lineRes = get_lines_with_boxes_4p(imageSrc, totalBoardBox, totalBoardThresWithAngle, boxList4p, transMtx,
                                              topRemain, leftRemain, bottomRemain, rightRemain, totalBoardOffset)
            cutLines, imageRes, boardLenthList, angleList, cutDisTotal, cutAreaTotal, isFirstCut, isThirdCut, cutWidth = lineRes
            print("算法耗时: {}".format(time.time() - calcStart))
            os.remove(filePathReal)
            imageRes = get_size_scale_image(imageRes, sizeScale=4)
            cv.imwrite(os.path.join(keepOkResPath, fileName), imageRes)
            cv.imwrite(os.path.join(keepOkPath, fileName), imageSrc)
            print(cutLines)
            print("识别成功!结果:切割面积:{},切割宽度:{},角度:{},长度:{}".format(cutAreaTotal, cutWidth, angleList, boardLenthList))
            continue
        else:
            print("算法耗时: {}".format(time.time() - calcStart))
            cv.imwrite(os.path.join(keepFailPath, fileName), imageSrc)
            os.remove(filePathReal)
            print("识别失败XXXXXXXXXXXXXXXXXXXXXXXXX")
            continue
